package com.example.myspringpro.exception;

import com.example.myspringpro.enums.ResultEnums;
import com.example.myspringpro.response.ResponseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.ModelMap;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description 统一异常处理类
 * @Author allenhu <huxiangneng@163.com>
 * @Date 2019/05/05
 * @Version V1.0.0
 **/
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    public static final String DEFAULT_ERROR_VIEW = "error";

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseData<?> validationErrorHandler(MethodArgumentNotValidException ex) {
        // 同样是获取BindingResult对象，然后获取其中的错误信息
        // 如果前面开启了fail_fast，事实上这里只会有一个信息
        // 如果没有，则可能又多个
        List<String> errorInformation = ex.getBindingResult().getAllErrors()
                .stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.toList());
        return new ResponseData<>(ResultEnums.VERIFY_CODE_ERROR.getCode(), errorInformation.toString());
    }

    /**
     * 自定义类处理
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(MyException.class)
    public ModelAndView handle(HttpServletRequest request, MyException ex) {
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", ex);
        mav.addObject("url", request.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseData handle(HttpServletRequest request, Exception e, HttpServletResponse response) {
        ResponseData result = new ResponseData();
        //如果是业务逻辑异常，返回具体的错误码与提示信息
        if(e instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) e;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                /* 打印验证不通过的信息*/
                result.setCode(ResultEnums.ERROR.getCode());
                result.setMsg(item.getMessage());
                break;
            }
        }else {
            result.setCode(ResultEnums.ERROR.getCode());
            result.setMsg(ResultEnums.ERROR.getMsg());
            //对系统级异常进行日志记录
            logger.error("系统异常:" + e.getMessage(), e);
        }
        return result;
    }
}
